Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add withProcess #53

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Add withProcess #53

wants to merge 1 commit into from

Conversation

dpwiz
Copy link

@dpwiz dpwiz commented Aug 13, 2023

A more general local for MonadReader r (Process r).

I don't like the name and open to suggestions.

Used like this:

host = runNode () do
  () <- ask
  forever do
    something <- interesting
    spawn $ withProcess (const something) session

session = do
  sessionLocalEnv <- ask
  ....    

@dpwiz
Copy link
Author

dpwiz commented Aug 15, 2023

It's unfortunate that that r belongs to NodeContext. Reader.local doesn't make sense this way since the computation proceeds in a Process, not on the node itself. Perhaps it would be more adequate to move the r into ProcessEnv proper.

@NicolasT
Copy link
Owner

I believe the intent was/is for all Processes on a node to have the very same environment. One reason to have it this way is for some "global" data to be shared, especially when some kind of supervisor would be responsible for spawning Processes. If the r is not node-global, the API for such supervisor could become quite a bit more complicated, I believe.

I'd be happy to be proven wrong, though!

@dpwiz
Copy link
Author

dpwiz commented Aug 16, 2023

They can share global data if that is what's needed downstream:

host :: Process Global ()
host = do
  localData <- setup...
  spawn onlyGlobal
  withProcessEnv (const localData) $ spawn onlyLocal
  withProcessEnv (, localData) $ spawn hasBoth
  ...

hasBoth :: Process (Global, Local) ()
  globalData <- asks fst
  ...

Of course if you need common data you don't want to drop it entirely.

And Process r is a MonadReader r, so that r can be changed per-process anyway with local :: (r -> r) -> .....

So the alternative is using awkward and non-total wrappers:

data GlobalAndLocal = Both
  { common :: Int
  , specific :: Maybe Socket -- awkward
  }

data GlobalOrLocal
  = Common Int
  | Specific Socket -- oops, lost that "global node data" anyway

@dpwiz
Copy link
Author

dpwiz commented Aug 16, 2023

I will try to lift env into process and see what happens...

Adds withProcessEnv (like withReaderT) - a more general `local` for MonadReader r (Process r).
@dpwiz
Copy link
Author

dpwiz commented Aug 16, 2023

It was pleasantly simple. The changes got contained in the runNode entry point and the rest rides along with the usual Reader stuff. The tests pass unchanged and user-facing API kept intact.

@NicolasT
Copy link
Owner

Hmh, I still wasn't able to remember why I made everything a ReaderT (basically) with the context stored at the node level...

In any case, given the change you suggested, does Process need to be a MonadReader at all? The only reason I can think of is to emulate Erlang's process dictionary, but then it should rather be a MonadState.

@dpwiz
Copy link
Author

dpwiz commented Aug 29, 2023

Maybe there shouldn't be a default MonadReader per se, just a bunch of functions to manipulate the process environment.

A user then can easily recover MonadReader just by plugging the functions manually. Alternatively, a user can use them to weld a reader-style effect system and have their stuff in there.

MonadState most certainly should not be provided as an effect that would back it should not be hardcoded. Some processes would like IORef-backed state, but some would vie for TMVar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants